<?php
namespace app\wap\controller;
use think\Controller;
use think\Db;
use think\Request;
use think\Validate;
use think\Loader;
use think\Model;
use think\Log;
use app\api\controller\KbxOrder;

class Wxpay extends Controller
{
    protected $appScrect="c1607dc9be1bd42153d0506e3220c877";//微信公众平台的appscrect
    protected $appId="wxd18e4dcd70f419f2";//微信公众平台appid
    protected $key="kuaibangxing12345678911111111111";//微信商户平台配置的秘钥
    protected $mch_id ='1313423601';//微信商户号
    protected $values = array();

    public function _initialize(Request $request = null)
    {
        header('Access-Control-Allow-Origin:*');
        Log::init([
            'type'  =>  'File',
            'path'  =>  APP_PATH.'logs/'
        ]);
    }


    //支付调用
    public function pay1()
    {
        $openid=input('openid');
        $order_id=input('order_id');
        $order_no=input('order_no');
        $orderType=input('orderType');

        $log["【pay1】调起微信支付"]=[
            'openid'=>$openid,
            'order_id'=>$order_id,
            'order_no'=>$order_no,
            'orderType'=>$orderType,
        ];
        Log::record($log);

        if (empty($order_id)) return json_encode(['msg'=>'缺少order_id','code'=>101]);

        //微信jsapi支付
        //判断是否在微信内部打开连接
        if ( strpos($_SERVER['HTTP_USER_AGENT'],'MicroMessenger') !== false )
        {
            if (empty($openid)){
                //当前端未传回openid时，先从库中用户表里查询已记录的openid，若存在就拿来使用
                $m_order = db("order")->where("order_id",$order_id)->field("member_id")->find();
                $custom_order = db("custom_made_order")->where("order_no",$order_no)->field("member_id")->find();
                if (empty($m_order) && empty($custom_order)) return json_encode(['msg'=>'订单错误','code'=>409]);
                $member_id = $m_order['member_id']??$custom_order['member_id'];
                $member = db("member")->where("member_id",$member_id)->field("wechat_openid")->find();
                if(!empty($member['wechat_openid'])){
                    $openid = $member['wechat_openid'];
                }else{
                    return json_encode(['msg'=>'缺少openid','code'=>102]);
                }
            }

            //判断订单类型，决定是否调用订单系统接口，存订单系统mongo库还是本系统mysql
            if(in_array($orderType,array("Vehicle","Custom","Other","Price_Gap","Self_Drive","Personal_Tailor","Subscription")))
            {//mysql
                $order= db('order')->alias('a')
                    ->where('a.order_id',$order_id)
                    ->join('goods g','g.goods_id=a.goods_id')
                    ->field('a.order_id,a.order_no,g.goods_name,a.fold_money,a.order_status')
                    ->find();

                if (empty($order)) return json_encode(['msg'=>'订单错误','code'=>400]);
                if ($order['order_status']!=1){
                    return json_encode(['msg'=>'订单已付款或已失效','code'=>401]);
                }
                $total_fee=$order['fold_money']*100;//金额
                $body='快帮行商品购买商品购买';//body
                $order_sn=$order['order_no'];//订单号
                $res=$this->pay($openid,$total_fee,$body,$order_sn);
            //}elseif(in_array($orderType,["Trip"])){//行程订单支付
            //    $trip = db("trip")->find($order_id);
            //    if (empty($trip)) return json_encode(['msg'=>'订单错误','code'=>400]);

            //    $total_fee=$trip['final_money']*100;//金额
            //    $body='快帮行个人定制行程支付';//body
            //    $order_sn=$trip['code'];//行程单号
            //    $res=$this->payTrip($openid,$total_fee,$body,$order_sn,$order_id);
            }else{//mongo
                $KbxOrder = new KbxOrder();
                $order = $KbxOrder->kbx_order_by_no($order_no);//获取订单信息

                if (empty($order)) return json_encode(['msg'=>'订单错误','code'=>400]);
                if ($order['status']['orderStatus']!=='pending' && $order['status']['paymentStatus']!=='pending'){
                    return json_encode(['msg'=>'订单已付款或已失效','code'=>401]);
                }
                if($orderType=='CustomMade'){
                    $total_fee=$order['payments']['online']['amount']*100;//金额
                    $body='快帮行定制行程支付';//body
                }else{
                    $total_fee=$order['payments']['foldMoney']*100;//金额
                    $body='快帮行商品购买';//body
                }
                $order_sn=$order_no;//订单号
                $res=$this->pay($openid,$total_fee,$body,$order_sn);
            }

            return json_encode(['msg'=>'ok','code'=>0,'data'=>$res]);
        }

        //H5支付
        //微信h5支付不用传递openid
        //判断订单类型，决定是否调用订单系统接口，存订单系统mongo库还是本系统mysql
        if(in_array($orderType,array("Vehicle","Custom","Other","Price_Gap","Self_Drive","Personal_Tailor","Subscription")))
        {//mysql
            $order= db('order')->alias('a')
                ->where('a.order_id',$order_id)
                ->join('goods g','g.goods_id=a.goods_id')
                ->field('a,order_id,a.order_no,g.goods_name,a.fold_money,a.order_status')
                ->find();

            if (empty($order)) return json_encode(['msg'=>'订单错误','code'=>101]);
            if ($order['order_status']!=1){
                return json_encode(['msg'=>'订单已付款或已失效','code'=>101]);
            }

            $total_fee=$order['fold_money']*100;//金额
            $body='快帮行商品购买';//body
            $order_sn=$order_no;//订单号

            $res=$this->payh5($total_fee,$body,$order_sn);
        }else{//mongo
            $KbxOrder = new KbxOrder();
            $order = $KbxOrder->kbx_order_by_no($order_no);//获取订单信息

            if (empty($order)) return json_encode(['msg'=>'订单错误','code'=>400]);
            if ($order['status']['orderStatus']!=='pending' && $order['status']['paymentStatus']!=='pending'){
                return json_encode(['msg'=>'订单已付款或已失效','code'=>401]);
            }

            if($orderType=='CustomMade'){
                $total_fee=$order['payments']['online']['amount']*100;//金额
                $body='快帮行定制行程支付';//body
            }else{
                $total_fee=$order['payments']['foldMoney']*100;//金额
                $body='快帮行商品购买';//body
            }
            $order_sn=$order_no;//订单号
            $res=$this->payh5($total_fee,$body,$order_sn);
        }

        return json_encode(['msg'=>'ok','code'=>0,'data'=>$res]);
    }


    public function pay($openid,$total_fee,$body,$out_trade_no){
        $config= config('wxpay');
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $notify_url = config('kbx_url').'/wap/Notify/notify';
        $onoce_str = $this->createNoncestr();
        $data["appid"] = $this->appId;
        $data["body"] = $body;
        $data["mch_id"] = $this->mch_id;
        $data["nonce_str"] = $onoce_str;
        $data["notify_url"] = $notify_url;
        $data["out_trade_no"] = $out_trade_no.'KBX'.time();
        $data["spbill_create_ip"] = $this->get_client_ip();
        $data["total_fee"] = $total_fee;
        $data["trade_type"] = "JSAPI";
        $data["openid"] = $openid;
        $sign = $this->getSign($data);
        $data["sign"] = $sign;

        $xml = $this->arrayToXml($data);
        $response = $this->postXmlCurl($xml, $url);

        //将微信返回的结果xml转成数组
        $response = $this->xmlToArray($response);
        $response['package']="prepay_id=".$response['prepay_id'];

        $jsapi=array();
        $timeStamp = time();
        $jsapi['appId']=($response["appid"]);
        $jsapi['timeStamp']=("$timeStamp");
        $jsapi['nonceStr']=($this->createNoncestr());
        $jsapi['package']=("prepay_id=" . $response['prepay_id']);
        $jsapi['signType']=("MD5");
        $jsapi['paySign']=($this->getSign($jsapi));
        $parameters =$jsapi;

        //请求数据,统一下单

        return $parameters;
    }

    public function payTrip($openid,$total_fee,$body,$out_trade_no,$trip_id){
        $config= config('wxpay');
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $notify_url   =config('kbx_url').'/wap/Notify/notify';
        $onoce_str = $this->createNoncestr();
        $data["appid"] = $this->appId;
        $data["body"] = $body;
        $data["mch_id"] = $this->mch_id;
        $data["nonce_str"] = $onoce_str;
        $data["notify_url"] = $notify_url;
        $data["out_trade_no"] = $out_trade_no.'KBX1230967564';
        $data["spbill_create_ip"] = $this->get_client_ip();
        $data["total_fee"] = $total_fee;
        $data["trade_type"] = "JSAPI";
        $data["openid"] = $openid;
        $data["attach"] = "trip-".$trip_id;
        $sign = $this->getSign($data);
        $data["sign"] = $sign;

        $xml = $this->arrayToXml($data);
        $response = $this->postXmlCurl($xml, $url);

        //将微信返回的结果xml转成数组
        $response = $this->xmlToArray($response);
        $response['package']="prepay_id=".$response['prepay_id'];

        $jsapi=array();
        $timeStamp = time();
        $jsapi['appId']=($response["appid"]);
        $jsapi['timeStamp']=("$timeStamp");
        $jsapi['nonceStr']=($this->createNoncestr());
        $jsapi['package']=("prepay_id=" . $response['prepay_id']);
        $jsapi['signType']=("MD5");
        $jsapi['paySign']=($this->getSign($jsapi));
        $parameters =$jsapi;

        //请求数据,统一下单

        return $parameters;
    }


    public function payh5($total_fee,$body,$out_trade_no){
        $ip= request()->ip();
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $notify_url   ='https://h.kuaibangxing.com/wap/Notify/notify';

        $onoce_str = $this->createNoncestr();

        $data["appid"] = $this->appId;
        $data["body"] = $body;
        $data["mch_id"] = $this->mch_id;
        $data["nonce_str"] = $onoce_str;
        $data["notify_url"] = $notify_url;
        $data["out_trade_no"] = $out_trade_no.'KBX1230967564';
        $data["spbill_create_ip"] = $ip;
        $data["total_fee"] = $total_fee;
        $data["trade_type"] = "MWEB";
        $data["scene_info"] = "{'h5_info': {'type':'Wap','wap_url': https://h.kuaibangxing.com,'wap_name': '商品购买'}}";
        $sign = $this->getSign($data);
        $data["sign"] = $sign;

        $xml = $this->arrayToXml($data);
        $response = $this->postXmlCurl($xml, $url);

        //将微信返回的结果xml转成数组
        $response = $this->xmlToArray($response);

        //请求数据,统一下单

        return $response;
    }

    //APP支付
    public function payApp($total_fee,$body,$out_trade_no,$appid){
        $ip= request()->ip();
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $notify_url   ='https://h.kuaibangxing.com/wap/Notify/notify';
        $onoce_str = $this->createNoncestr();

        $data["appid"] = $appid;
        $data["body"] = $body;
        $data["mch_id"] = $this->mch_id;
        $data["nonce_str"] = $onoce_str;
        $data["notify_url"] = $notify_url;
        $data["out_trade_no"] = $out_trade_no.'KBX1230967564';
        $data["spbill_create_ip"] = $ip;
        $data["total_fee"] = $total_fee;
        $data["trade_type"] = "APP";
        $sign = $this->getSign($data);
        $data["sign"] = $sign;

        $xml = $this->arrayToXml($data);
        //请求数据,统一下单
        $response = $this->postXmlCurl($xml, $url);
        //将微信返回的结果xml转成数组
        $response = $this->xmlToArray($response);

        //第二次签名  带prepay_id
        $data2["appid"] = $response['appid'];
        $data2["partnerid"] = $response['mch_id'];
        $data2["prepayid"] = $response['prepay_id'];
        $data2["noncestr"] = $response['nonce_str'];
        $data2["package"] = "Sign=WXPay";
        $data2["timestamp"] = time();
        $sign2 = $this->getSign($data2);
        $data2["sign"] = $sign2;

        $log["【payh5】统一订单支付"]=[
            '【第一次】签名接口data'=>json_encode($data),
            '【第一次】签名接口return'=>json_encode($response),
            '【最终返回】'=>json_encode($data2),
        ];
        Log::record($log);

        return $data2;
    }



    public static function getNonceStr($length = 32)
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str ="";
        for ( $i = 0; $i < $length; $i++ )  {
            $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
        }
        return $str;
    }

    // 　　/*生成签名*/
    public function getSign($Obj){
        foreach ($Obj as $k => $v){
            $Parameters[$k] = $v;
        }
        //签名步骤一：按字典序排序参数
        ksort($Parameters);
        $String = $this->formatBizQueryParaMap($Parameters, false);
        //echo '【string1】'.$String.'</br>';
        //签名步骤二：在string后加入KEY
        $String = $String."&key=".$this->key;
        //echo "【string2】".$String."</br>";
        //签名步骤三：MD5加密
        $String = md5($String);
        //echo "【string3】 ".$String."</br>";
        //签名步骤四：所有字符转为大写
        $result_ = strtoupper($String);
        //echo "【result】 ".$result_."</br>";
        return $result_;
    }


    /**
     *  作用：产生随机字符串，不长于32位
     */
    public function createNoncestr( $length = 32 ){
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str ="";
        for ( $i = 0; $i < $length; $i++ )  {
            $str.= substr($chars, mt_rand(0, strlen($chars)-1), 1);
        }
        return $str;
    }


    //数组转xml
    public function arrayToXml($arr){
        $xml = "<xml>";
        foreach ($arr as $key=>$val){
            if (is_numeric($val)){
                $xml.="<".$key.">".$val."</".$key.">";
            }else{
                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
            }
        }
        $xml.="</xml>";
        return $xml;
    }


    /**
     *  作用：将xml转为array
     */
    public function xmlToArray($xml){
        //将XML转为array
        $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $array_data;
    }


    /**
     *  作用：以post方式提交xml到对应的接口url
     */
    public function postXmlCurl($xml,$url,$second=30){
        //初始化curl
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        //这里设置代理，如果有的话
        //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        curl_setopt($ch,CURLOPT_URL, $url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        //运行curl
        $data = curl_exec($ch);
        //返回结果

        if($data){
            curl_close($ch);
            return $data;
        }else{
            $error = curl_errno($ch);
            echo "curl出错，错误码:$error"."<br>";
            curl_close($ch);
            return false;
        }
    }


    /*
    获取当前服务器的IP
    */
    public function get_client_ip(){
        if ($_SERVER['REMOTE_ADDR']) {
            $cip = $_SERVER['REMOTE_ADDR'];
        } elseif (getenv("REMOTE_ADDR")) {
            $cip = getenv("REMOTE_ADDR");
        } elseif (getenv("HTTP_CLIENT_IP")) {
            $cip = getenv("HTTP_CLIENT_IP");
        } else {
            $cip = "unknown";
        }
        return $cip;
    }


    /**
     *  作用：格式化参数，签名过程需要使用
     */
    public function formatBizQueryParaMap($paraMap, $urlencode){
        $buff = "";
        ksort($paraMap);
        foreach ($paraMap as $k => $v){
            if($urlencode){
                $v = urlencode($v);
            }
            $buff .= $k . "=" . $v . "&";
        }
        $reqPar;
        if (strlen($buff) > 0){
            $reqPar = substr($buff, 0, strlen($buff)-1);
        }
        return $reqPar;
    }

    public function MakeSign($unifiedorder)
    {
        $this->values=$unifiedorder;
        //签名步骤一：按字典序排序参数
        // ksort($this->values);
        $string = $this->ToUrlParams();
//		halt($string);
        //签名步骤二：在string后加入KEY
        $string = $string . "&key=".$this->key;
        //签名步骤三：MD5加密
        $string = md5($string);
        //签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    public function ToUrlParams()
    {
        $buff = "";
        foreach ($this->values as $k => $v)
        {
            if($k != "sign" && $v != "" && !is_array($v)){
                $buff .= $k . "=" . $v . "&";
            }
        }

        $buff = trim($buff, "&");
        return $buff;
    }


    function array2xml($array)
    {
        $xml='<xml>';
        foreach($array as $key=>$val){
            if(is_numeric($key)){
                $key="item id=\"$key\"";
            }else{
                //去掉空格，只取空格之前文字为key
                list($key,)=explode(' ',$key);
            }
            $xml.="<$key>";
            $xml.=is_array($val)?$this->array2xml($val):$val;
            //去掉空格，只取空格之前文字为key
            list($key,)=explode(' ',$key);
            $xml.="</$key>";

        }
        $xml.="</xml>";

        return $xml;
    }

    function xml2array($xml)
    {
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $values;
    }


    public  function request_post($url = '', $param = '')
    {
        if (empty($url) || empty($param)) {
            return false;
        }
        $postUrl = $url;
        $curlPost = $param;
        $ch = curl_init(); //初始化curl
        curl_setopt($ch, CURLOPT_URL, $postUrl); //抓取指定网页
        curl_setopt($ch, CURLOPT_HEADER, 0); //设置header
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_POST, 1); //post提交方式
        curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost);
        $data = curl_exec($ch); //运行curl
        curl_close($ch);
        return $data;
    }

    function curl_post_ssl($url, $vars, $second=30,$aHeader=array())
    {
        $ch = curl_init();
        //curl_setopt($ch,CURLOPT_VERBOSE,'1');
        curl_setopt($ch,CURLOPT_TIMEOUT,$second);
        curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch,CURLOPT_URL,$url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);
        curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
        curl_setopt($ch,CURLOPT_SSLCERT,'/data/cert/php.pem');
        curl_setopt($ch,CURLOPT_SSLCERTPASSWD,'1234');
        curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
        curl_setopt($ch,CURLOPT_SSLKEY,'/data/cert/php_private.pem');

        if( count($aHeader) >= 1 ){
            curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);
        }

        curl_setopt($ch,CURLOPT_POST, 1);
        curl_setopt($ch,CURLOPT_POSTFIELDS,$vars);
        $data = curl_exec($ch);
        curl_close($ch);
        if($data){

            return $data;

        }else{
            return false;

        }

    }
}